use crate::{config, data::VCData};

#[derive(Debug)]
pub struct FastVotingRule;

impl FastVotingRule {
    pub fn new() -> Self {
        FastVotingRule {}
    }

    /// 是否为有效的投票
    pub fn voting(&self, my: &VCData, v: &VCData, max_weight: &usize) -> bool {
        // 当没有票的时候，拒绝其他节点的投票，不考虑暂存的票
        // if my.poll == 0 {
        //     log::info!(
        //         "[{}] - [{}] - Voting by poll is invalid, my.poll = {}, v.poll = {} I am a voter.",
        //         my.myid,
        //         v.myid,
        //         my.poll,
        //         v.poll,
        //     );
        //     return false;
        // }

        if let Some(valid_or_not) = self.voting_with_term(my, v) {
            return valid_or_not;
        }

        if let Some(valid_or_not) = self.voting_with_tranx(my, v) {
            return valid_or_not;
        }

        if let Some(valid_or_not) = self.voting_with_weight(my, v, max_weight) {
            return valid_or_not;
        }

        self.voting_with_id(my, v)
    }

    /// 通过投票周期判断，是否为有效的投票
    #[inline]
    fn voting_with_term(&self, my: &VCData, v: &VCData) -> Option<bool> {
        // 投票周期
        if my.term < v.term {
            // 无效投票
            log::info!(
                "Voting by term is invalid, my.term = {}, v.term = {}",
                my.term,
                v.term
            );
            Some(false)
        } else if my.term == v.term {
            // 投票无结果
            log::info!(
                "Voting by term is undecided, my.term = {}, v.term = {}",
                my.term,
                v.term
            );
            None
        } else {
            // 投票成功
            log::info!(
                "Voting by term is ok, my.term = {}, v.term = {}",
                my.term,
                v.term
            );
            Some(true)
        }
    }

    /// 通过事务ID比较判断，是否为有效的投票
    #[inline]
    fn voting_with_tranx(&self, my: &VCData, v: &VCData) -> Option<bool> {
        // 事务ID比较
        if my.tranx < v.tranx {
            // 无效投票
            log::info!(
                "Voting by tranx is invalid, my.tranx = {}, v.tranx = {}",
                my.tranx,
                v.tranx
            );
            Some(false)
        } else if my.tranx == v.tranx {
            // 投票无结果
            log::info!(
                "Voting by tranx is undecided, my.tranx = {}, v.tranx = {}",
                my.tranx,
                v.tranx
            );
            None
        } else {
            // 投票成功
            log::info!(
                "Voting by tranx is ok, my.tranx = {}, v.tranx = {}",
                my.tranx,
                v.tranx
            );
            Some(true)
        }
    }

    /// 通过Weight比较判断，是否为有效的投票
    #[inline]
    fn voting_with_weight(&self, my: &VCData, v: &VCData, max_weight: &usize) -> Option<bool> {
        // my.weight=555
        // max_weight=999
        // v.weight=123
        // 123 < 555
        // 123 < 555 && 555 < 999
        if (v.weight < my.weight && my.weight < *max_weight) || my.weight < v.weight {
            // 自身权重比最大权重小
            // 无效投票
            log::info!(
                "Voting by weight is invalid, my.weight = {}, v.weight = {}, max_weight = {}",
                my.weight,
                v.weight,
                max_weight
            );
            return Some(false)
        }

        // 比较权重
        if my.weight == v.weight {
            // 投票无结果
            log::info!(
                "Voting by weight is undecided, my.weight = {}, v.weight = {}, max_weight = {}",
                my.weight,
                v.weight,
                max_weight
            );
            None
        } else {
            // 投票成功
            log::info!(
                "Voting by weight is ok, my.weight = {}, v.weight = {}, max_weight = {}",
                my.weight,
                v.weight,
                max_weight
            );
            Some(true)
        }
    }

    /// 通过ServerID比较判断，是否为有效的投票
    #[inline]
    fn voting_with_id(&self, my: &VCData, v: &VCData) -> bool {
        // ServerID比较
        if my.myid < v.myid {
            // 无效投票
            log::info!(
                "Voting by myid is invalid, my.myid = {}, v.myid = {}",
                my.myid,
                v.myid
            );
            false
        } else {
            // 投票成功
            log::info!(
                "Voting by myid is ok, my.myid = {}, v.myid = {}",
                my.myid,
                v.myid
            );
            true
        }
    }
}

#[derive(Debug)]
pub struct FastElectingRule {
    // 全部参与者
    // candidate_count: usize,
    // 最小参与者
    quorum: usize,
    // 最小持有票数 = 最小参与者
    min_held_poll: usize,
}

impl FastElectingRule {
    pub fn new() -> Self {
        let candidate_count = config::get_members().len();
        let quorum = if candidate_count % 2 == 1 {
            // 奇数 odd
            (candidate_count + 1) / 2
        } else {
            // 偶数 even
            candidate_count / 2
        };

        FastElectingRule {
            // candidate_count,
            quorum,
            min_held_poll: quorum,
        }
    }

    // 选举
    // 如果节点没有过半，则无法进入选举
    // 当前参与者数量 loc.active_nodes.len()
    pub fn electing(&self, online_count: usize, my: &VCData) -> bool {
        // Leading 或 Following 无需进入选举流程
        // match status {
        //     Status::Leading | Status::Following => return None,
        //     _ => {},
        // }

        // 至少超过一半存活，否则返回 选举失败
        if online_count < self.quorum {
            log::info!(
                "Lack a quorum in Voting, expect {}, now {}",
                self.quorum,
                online_count
            );
            return false;
        }

        // 当前持有的票数 > 最小持有持有票数，否则返回 选举失败
        if my.poll < self.min_held_poll {
            log::info!(
                "Lack of poll in Voting, expect {}, now {}",
                self.min_held_poll,
                my.poll,
            );
            return false;
        }

        true
    }

    // leader 是否有效，主要判断当前存活的节点数，与最小节点数判断
    pub fn is_valid(&self, online_count: usize) -> bool {
        // 至少超过一半存活，否则返回 选举失败
        if online_count >= self.quorum {
            return true;
        }

        false
    }

    pub fn quorum(&self) -> usize {
        self.quorum
    }


}
